package com.stone.starter.core.util.proxy;

import org.springframework.beans.factory.ObjectFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理创建工具（基于JDK代理），来自：{@link org.springframework.security.oauth2.common.util}
 *
 * @author Mr_wenpan@163.com 2021/11/13 3:35 下午
 */
public class ProxyCreator {

    private static final String EQUALS = "equals";
    private static final String HASH_CODE = "hashCode";

    /**
     * 生成代理对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getProxy(Class<T> type, ObjectFactory<T> factory) {
        return (T) Proxy.newProxyInstance(ProxyCreator.class.getClassLoader(), new Class<?>[]{type},
                new LazyInvocationHandler<T>(factory));
    }

    private static class LazyInvocationHandler<T> implements InvocationHandler {

        private T target;

        private final ObjectFactory<T> factory;

        public LazyInvocationHandler(ObjectFactory<T> factory) {
            this.factory = factory;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // Invocation on interface coming in...
            if (EQUALS.equals(method.getName())) {
                return (proxy == args[0]);
            } else if (HASH_CODE.equals(method.getName())) {
                return System.identityHashCode(proxy);
            }
            try {
                return method.invoke(getTarget(method), args);
            } catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }

        private Object getTarget(Method method) {
            if (target == null) {
                target = factory.getObject();
            }
            return target;
        }

    }
}